/*
 * CommandLineParsers.cpp
 *
 *  Created on: Apr 3, 2010
 *      Author: Lukasz Spintzyk
 */

#include "CommandLineParsers.h"
#include "ph.h"
#include <boost/program_options.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>

#include "version.h"
#include "utils.h"
#include "Inode.h"


FilesystemMkfsArgs::FilesystemMkfsArgs()
	:blockSize(1024)
	,blocksPerGroup(blockSize*8)
	,groupsCount(100)
    ,inodesPerGroup((blockSize/Inode::size() * (blocksPerGroup/10)))
    ,checkInterval(100*24*3600)
    ,maxMntCount(20)
{
	    //default values
}


struct FilesystemMkfsArgs parseMkfsArgs(int argc, char* argv[])
{
	struct FilesystemMkfsArgs mkfs_args;

    namespace po = boost::program_options;
    po::options_description desc("Options");
    desc.add_options()
        ("help,h", "produce help message")
        ("version,v", "print version string")
        ("device,d", po::value< std::string >(), "Place to store filesystem, device of file")
        ("key", po::value<std::string>(), "Symetric 128 bit aes key, hexadecimal format 00::11:: ..")
        ("IV", po::value<std::string>(), "Initialization vector. 128 bit hexadecimal value")
        ("blockSize", po::value< uint32_t >(), "Size of block. Accepted values 1024, 2048, 4096, 8192. Default 1024")
        ("blocksPerGroup", po::value< uint32_t >(), "Number of blocks in Block Group. default 8192")
        ("inodesPerGroup", po::value< uint32_t >(), "Number of inodes in Block Group.")
        ("checkinterval", po::value< uint32_t >(), "Number of day between filesystem check")
        ("groupNum", po::value< uint32_t >(), "Groups Count")
        ("maxMntCount", po::value< uint32_t >(), "Number of filesystem mounts between check");



    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    mkfs_args.mount.exit = true;

    if (vm.empty())
    {

        return mkfs_args;
    }

    if (vm.count("help"))
    {
        std::cout << desc << std::endl;
        return mkfs_args;
    }

    if (vm.count("version"))
    {
        std::cout << VERSION_STR << " " << VERSION << std::endl;
        return mkfs_args;
    }


    if (vm.count("device"))
    {
        mkfs_args.mount.file = vm["device"].as< std::string >();
        // TODO delete std::cout << "device : "<< fs_options.file  << std::endl;
    }
    else
    {
        std::cout << "You must set the device" << std::endl;
        return mkfs_args;
    }

    if (vm.count("IV"))
    {
        std::string iv = vm["IV"].as< std::string >();
        //uint32_t size = (iv.size() <=32) ? iv.size() : 32;
        if (iv[2] == ':' && iv.size() <= 32){
        	mkfs_args.mount.iv = remove_dots(iv);
        }
        else
        {
        	mkfs_args.mount.iv = iv;
        }
    }
    if (!vm.count("IV") || mkfs_args.mount.iv.size() < 32)
    {
    	mkfs_args.mount.iv = "1122334455667788A1A2A3A4A5A6A7A8";
    }

    if (vm.count("key"))
    {
        std::string key = vm["key"].as< std::string >();
        //uint32_t size = (key.size() <=32) ? key.size() : 32;
        if (key[2] == ':' && key.size() <= 32){
        	mkfs_args.mount.key = remove_dots(key); // TODO add size param
        }
        else
        {
        	mkfs_args.mount.key = key;
        }

    }
    else
    {
        std::cout << "You must specify cryptographic key"<< std::endl;
        return mkfs_args;
    }

    if (vm.count("blockSize"))
    {
        uint32_t bs = vm["blockSize"].as< uint32_t >();
        if (bs < 1024 || ((bs%1024) != 0))
        {
        	std::cout << std::endl << "Bad block size value expected 1024, 2048, 4098 or 8129" << std::endl;
        	return mkfs_args;
        }
        mkfs_args.blockSize = bs;
    }

    if (vm.count("blocksPerGroup"))
    {
        uint32_t bs = vm["blocksPerGroup"].as< uint32_t >();
        if (bs > mkfs_args.blockSize*8)
        {
        	std::cout << std::endl << "Bad block per group number" << std::endl;
        	return mkfs_args;
        }
        mkfs_args.blocksPerGroup = bs;
    }

    if (vm.count("inodesPerGroup"))
    {
        uint32_t bs = vm["inodesPerGroup"].as< uint32_t >();
        if (bs > mkfs_args.blockSize*8)
        {
        	std::cout << std::endl << "Bad inodes per group number" << std::endl;
        	return mkfs_args;
        }
        mkfs_args.inodesPerGroup = bs;
    }

    if (vm.count("checkinterval"))
    {
    	mkfs_args.checkInterval = vm["checkinterval"].as< uint32_t >() * 24*3600;
    }

    if (vm.count("groupNum"))
	{
		mkfs_args.groupsCount = vm["groupNum"].as< uint32_t >();
	}

    if (vm.count("maxMntCount"))
	{
		mkfs_args.maxMntCount = vm["maxMntCount"].as< uint32_t >();
	}

    mkfs_args.mount.exit = false;

	return mkfs_args;
}

struct FilesystemMountArgs parseMountArgs(int argc, char* argv[])
{
	struct FilesystemMountArgs mount_args;

	namespace po = boost::program_options;
    po::options_description desc("Mount options");
    desc.add_options()
        ("help,h", "produce help message")
        ("version,v", "print version string")
        ("debug,d", "run in debug mode")
        ("single,s", "run in single threaded mode")
        ("device", po::value< std::string >(), "Place to store filesystem, device of file")
        ("key", po::value<std::string>(), "Symetric 128 bit aes key, hexadecimal format 00::11:: ..")
        ("IV", po::value<std::string>(), "Initialization vector. 128 bit hexadecimal value")
        ("mountpoint", po::value<std::string>(), "Place to mount filesystem");



    po::positional_options_description pos_desc;
    pos_desc.add("mountpoint", 1); // TODO handle exceptions for bad commandline (mulitiple pos opts)


    po::variables_map vm;
    po::store(po::command_line_parser(argc, argv).options(desc).positional(pos_desc).run(), vm);
    po::notify(vm);

    mount_args.exit = true;

    if (vm.empty())
    {
    	return mount_args;
    }

    if (vm.count("help"))
    {
        std::cout << desc << std::endl;
        return mount_args;
    }

    if (vm.count("version"))
    {
        std::cout << VERSION_STR << " " << VERSION << std::endl;
        return mount_args;
    }


    if (vm.count("device"))
    {
        mount_args.file = vm["device"].as< std::string >();
        // TODO delete std::cout << "device : "<< fs_options.file  << std::endl;
    }
    else
    {
        std::cout << "You must set the device" << std::endl;
        return mount_args;
    }

    if (vm.count("mountpoint"))
    {
    	mount_args.mountpoint = vm["mountpoint"].as< std::string >();
    }
    else
    {
    	std::cout << "You must specify mountpoint!" << std::endl;
    	return mount_args;
    }


    if (vm.count("key"))
    {
        std::string key = vm["key"].as< std::string >();
        //uint32_t size = (key.size() <=32) ? key.size() : 32;
        if (key[2] == ':' && key.size() <= 32){
        	mount_args.key = remove_dots(key); // TODO add size param
        }
        else
        {
        	mount_args.key = key;
        }

    }
    else
    {
        std::cout << "You must specify cryptographic key"<< std::endl;
        return mount_args;
    }

    if (vm.count("IV"))
    {
        std::string iv = vm["IV"].as< std::string >();
        if (iv[2] == ':'){
        	mount_args.iv = remove_dots(iv);
        }
        else
        {
        	mount_args.iv = iv;
        }
    }
    if (!vm.count("IV") || mount_args.iv.size() < 32)
    {
    	mount_args.iv = "1122334455667788A1A2A3A4A5A6A7A8";
    }

    mount_args.exit = false;


	return mount_args;
}
